#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <ctype.h>

#define NR_CPU 2
#define USAGE 20
#define PERIOD 10000
#define USECS_PER_SECOND (1000 * 1000)
static int use_threads = 0;

static void do_cal()
{
    int i;
    int y = 0;
    for (i = 0; i < 100; i++) {
        y = (i + y) * (y - i);
    }
}

static inline unsigned long long get_usec()
{
        struct timeval now;
        gettimeofday(&now, NULL);
        return (now.tv_sec * USECS_PER_SECOND + now.tv_usec);
}

static void run(void *data)
{
    int percent = (int)data;
    struct timeval start, now;

    if (percent > 100)
        percent = 100;

    if (percent < 0)
        percent = 0;

    unsigned long long on = PERIOD * (float)percent / 100;
    unsigned long long off = PERIOD * ((float)(100 - percent) / 100); 

    while (1) {
        unsigned long long start_usec = get_usec();

        while (get_usec() - start_usec < on) {
            do_cal();
        }

        usleep(off);
	}
}

static void usage()
{
    printf("Usage: [-h] [-c process num ] [ -u cpusuage ] \n");
    printf("options:\n");
    printf("-h: help message\n");
    printf("-c: process number, default 2\n");
    printf("-l: threads number, default 2\n");
    printf("-u: cpu utilization, range from [0, 100], default 20 \n");
}

int main(int argc, char **argv)
{
	int i;
    int cpu = NR_CPU;
    int cpu_util = USAGE;
    int c;

    while ((c = getopt(argc, argv, "hl:c:u:")) != -1) {
        switch (c) {
        case 'c':
            cpu = atol(optarg);  
            break;
        case 'l':
            cpu = atol(optarg);
            use_threads = 1;
            break;
        case 'u':
            cpu_util = atol(optarg);
            break;
        case 'h':
            usage();
            exit(0);
        default:
            printf("invalid option %c\n", c);
            usage();
            exit(1);
        }
    }


    if (use_threads == 1) {
        pthread_t *tids = malloc(sizeof(pthread_t) * cpu);
        if (tids == NULL) {
            fprintf(stderr, "can not alloc memory\n");
            exit(1);
        }

        printf("main: use %d child threads ...\n\n", cpu);
        for (i = 0; i < cpu; i++) {
            if (pthread_create(&tids[i], NULL, run, cpu_util) < 0) {
                fprintf(stderr, "pthread create error\n");
                exit(1);
            }
        }

        for (i = 0; i < cpu; i++) {
            void *ret;
            pthread_join(tids[i], &ret);
        }

        free(tids);
    } else {
        pid_t *pids = malloc(sizeof(pid_t) * cpu);
        if (pids == NULL) {
            fprintf(stderr, "can not alloc memory\n");
            exit(1);
        }

        printf("main: fork %d child process ...\n\n", cpu);
        for (i = 0; i < cpu; i++) {
            pid_t pid = fork();
            if (pid == 0) {
                run((void*)cpu_util);
                exit(0);
            } else if (pid < 0) {
                printf("fork error: %s\n", strerror(errno));

            }
            pids[i] = pid;
        }

        printf("pids:\n");
        for (i = 0; i < cpu; i++)
            printf("%ld ", pids[i]);

        printf("\n");

        free(pids);
    }
	
	return 0;
}
